/*
 * Copyright 2004-2006 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package uk.co.foocode.sample.petclinic.hibernate;

import java.sql.SQLException;
import java.util.Collection;
import java.util.Date;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.type.Type;
import org.springframework.beans.support.PagedListHolder;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import uk.co.foocode.sample.petclinic.Clinic;
import uk.co.foocode.sample.petclinic.Owner;
import uk.co.foocode.sample.petclinic.Pet;
import uk.co.foocode.sample.petclinic.Vet;
import uk.co.foocode.sample.petclinic.Visit;
import uk.co.foocode.sample.petclinic.util.PagedListResults;

/**
 * Hibernate implementation of the Clinic interface.
 * 
 * <p>
 * The mappings are defined in "petclinic.hbm.xml", located in the root of the
 * class path.
 * 
 * @author Juergen Hoeller
 * @since 19.10.2003
 */
public class HibernateClinic extends HibernateDaoSupport implements Clinic {

    public Collection getPets() throws DataAccessException {
    	
    	getHibernateTemplate().find("count(*) from Pet");
    	return getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery("from Pet pet order by pet.name");
				query.setCacheable(true);
				return query.list();
			}});
    	
//        return getHibernateTemplate().find("from Pet pet order by pet.name");
    }

    public Collection getVets() throws DataAccessException {
        return getHibernateTemplate().find("from Vet vet order by vet.lastName, vet.firstName");
    }

    public Collection getPetTypes() throws DataAccessException {
        return getHibernateTemplate().find("from PetType type order by type.name");
    }

    public Collection findOwners(String lastName) throws DataAccessException {
        return getHibernateTemplate().find("from Owner owner where owner.lastName like ? order by owner.lastName,owner.firstName", lastName + "%");
    }

    public Owner loadOwner(int id) throws DataAccessException {
        return (Owner) getHibernateTemplate().load(Owner.class, new Integer(id));
    }

    public Pet loadPet(int id) throws DataAccessException {
        return (Pet) getHibernateTemplate().load(Pet.class, new Integer(id));
    }

    public void storeOwner(Owner owner) throws DataAccessException {
        // Note: Hibernate3's merge operation does not re-associate the object
        // with the
        // current Hibernate Session. Instead, it will always copy the state
        // over to
        // a registered representation of the entity. In case of a new entity,
        // it will
        // register a copy as well, but will not update the id of the passed-in
        // object.
        // To still update the ids of the original objects too, we need to
        // register
        // Spring's IdTransferringMergeEventListener on our SessionFactory.
        getHibernateTemplate().merge(owner);
    }

    public void storePet(Pet pet) throws DataAccessException {
        getHibernateTemplate().merge(pet);
    }

    public void storeVisit(Visit visit) throws DataAccessException {
        getHibernateTemplate().merge(visit);
    }

	public Collection findVisits(Date startDate, Date endDate)
			throws DataAccessException {
    	Integer rowCount= (Integer) getHibernateTemplate().iterate("select count(*) from Visit visit where visit.date between ? and ? ",new Object[]{startDate,endDate}).next();
        return getHibernateTemplate().find("from Visit visit where visit.date between ? and ? order by visit.date",new Object[]{startDate,endDate});
	}
	public PagedListResults findVisits(final Date startDate, final Date endDate, final int rowOffset,final int rowLimit)
	throws DataAccessException {
		
    	return (PagedListResults) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				
				Query countQuery = session.createQuery("select count(*) from Visit visit where visit.date between ? and ?");
				countQuery.setCacheable(true);
				countQuery.setCacheRegion("queries.VisitsByDate");
				countQuery.setDate(0, startDate);
				countQuery.setDate(1, endDate);
				Long rowCount =(Long) countQuery.iterate().next();
				Query query = session.createQuery("from Visit visit where visit.date between ? and ? order by visit.date");
				query.setDate(0, startDate);
				query.setDate(1, endDate);
				query.setCacheable(true);
				query.setCacheRegion("queries.VisitsByDate");
				query.setMaxResults(rowLimit);   
				query.setFirstResult(rowOffset);
				PagedListResults results = new PagedListResults(query.list(),rowCount.intValue());
				results.setOffset(rowOffset);
				results.setLimit(rowLimit);
				return results;
			}});
	}

	public Collection getSpecialties() throws DataAccessException {
        return getHibernateTemplate().find("from Specialty specialty order by specialty.name");
	}

	public void storeVet(Vet vet) throws DataAccessException {
        getHibernateTemplate().merge(vet);
	}

	public Visit loadVisit(int id) throws DataAccessException {
        return (Visit) getHibernateTemplate().load(Visit.class, new Integer(id));
	}
	public Vet loadVet(int id) throws DataAccessException {
		return (Vet) getHibernateTemplate().load(Vet.class, new Integer(id));
	}

}
